//
//  RSController.m
//  RemoteSay
//
//  Created by Jan Lehnardt on 16/03/2007.
//  Copyright 2007 Jan Lehnardt. All rights reserved.
//

#import "RSController.h"
#import "RSMessageProtocol.h"
#include <sys/socket.h>

#import <Carbon/Carbon.h>
#import <SystemConfiguration/SystemConfiguration.h>

@implementation RSController

-(id)init
{
	self = [super init];
	
	historyData = [[NSMutableArray alloc] initWithCapacity:20]; // todo: move to init
	historyDataString = [[NSMutableString alloc] initWithCapacity:100]; // todo: move to init

	
	return self;
}

-(void)awakeFromNib
{
	//launch server
	[NSThread  detachNewThreadSelector:@selector(launchServer:) toTarget:self withObject:nil];
	
	browser = [[NSNetServiceBrowser alloc] init];
	services = [[NSMutableArray array] retain];
	[browser setDelegate:self];
	[browser searchForServicesOfType:@"_remotesay._tcp" inDomain:@"local."];
	NSLog(@"browsing started");
	[historyDataString appendString:@"history"];
	
}

-(void)dealloc
{
	[historyData release];
	[historyDataString release];
	[super dealloc];
}

-(void) netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindService:(NSNetService *)aNetService moreComing:(BOOL)moreComing
{
	NSLog(@"Found a service");
	[services addObject:aNetService];
	if(!moreComing) {
		[target setNumberOfVisibleItems: [services count]];
		[target reloadData];
	}
}

-(void) netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didRemoveService:(NSNetService *)aNetService moreComing:(BOOL)moreComing
{
	NSLog(@"Lost a service");
	NSEnumerator *enumerator = [services objectEnumerator];
	NSNetService *currentNetService;
	
	while(currentNetService = [enumerator nextObject]) {
		if([[currentNetService name] isEqual:[aNetService name]] &&
		[[currentNetService type] isEqual:[aNetService type]] &&
		[[currentNetService domain] isEqual:[aNetService domain]]) {
			[services removeObject:currentNetService];
			break;
		}
	}
	
	if(!moreComing) {
		[target setNumberOfVisibleItems: [services count]];
		[target reloadData];
	}
}

-(int)numberOfItemsInComboBox:(NSComboBox *)aComboBox
{
	return [services count];
}

-(id)comboBox:(NSComboBox *)aComboBox objectValueForItemAtIndex:(int)index
{
	NSNetService *item;
	item = [services objectAtIndex:index];
	return [item name];
}

-(unsigned int)comboBox:(NSComboBox *)aComboBox indexOfItemWithStringValue:(NSString *)string
{
	unsigned int k, max;
	NSNetService *item;
	max = [services count];
	for(k = 0; k < max; k++) {
		item = [services objectAtIndex:k];
		if([string isEqual:[item name]]) {
			return k;
		}
	}
	
	return 0;
}

-(void)launchServer:(id)object
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	NSRunLoop *runloop = [NSRunLoop currentRunLoop];
	
	NSSocketPort *receivePort;
	
	@try {
		receivePort = [[NSSocketPort alloc] initWithTCPPort:12354];
	} @catch (NSException *e ) {
		NSLog(@"Can't get Port 12354");
	}
	
	NSConnection *connection;
	connection = [NSConnection connectionWithReceivePort:receivePort sendPort:nil];
	
	[receivePort release]; //gets retained by connection
	[connection setRootObject:self];
	
	//set p monitoring, page 454
	
	//bonjour!
	
	NSNetService *netService;
	netService = [[NSNetService alloc] initWithDomain:@"" type:@"_remotesay._tcp" name:[(id)SCDynamicStoreCopyComputerName(NULL, NULL) autorelease] port:12354];
	//set monitor delegate
	[netService publish];
	
	NSLog(@"server's up");
	[runloop run];
	//cleanup if runloop exists
	[connection release];
	[pool release];
}

-(oneway void)say:(in bycopy NSString*)msg
{
	NSTask *say = [[NSTask alloc] init];
	[say setLaunchPath:@"/usr/bin/say"];
	[say setArguments:[NSArray arrayWithObjects: msg, nil]];
	[say launch];
	[say waitUntilExit];
	[say release];
}

-(IBAction)sayRemote:(id)sender
{
	NSLog(@"Say %@ to %@", [message stringValue], [target stringValue]);
	
	NSNetService *currentService;
	currentService = [services objectAtIndex:[target indexOfSelectedItem]];
	[currentService setDelegate:self];
	[currentService resolveWithTimeout:10];
}

-(void)netServiceDidResolveAddress:(NSNetService *)currentService
{
	NSArray *addresses;
	addresses = [currentService addresses];
	if([addresses count] > 0) {
		[self remoteSay:[addresses objectAtIndex:0]];
	}
}



-(void)remoteSay:(NSData *)address
{
	NSConnection *connection;
	NSSocketPort *sendPort;	
	sendPort = [[NSSocketPort alloc] initRemoteWithProtocolFamily:AF_INET socketType:SOCK_STREAM protocol:INET_TCP address:address];

	connection = [NSConnection connectionWithReceivePort:nil sendPort:sendPort];
	[connection setRequestTimeout:10.0];
	[connection setReplyTimeout:10.0];
	
	[sendPort release]; //gets retained by connection
	
	id proxy;
	@try {
		proxy = [[connection rootProxy] retain];
		
		//add connection failure info
		[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(connectionDown:) name:NSConnectionDidDieNotification object:connection];
//		[proxy setProtocolForProxy:@protocol(RSMessage)];

		NSLog(@"before say");
		[proxy say:[message stringValue]];
//		[historyData addObject:message];
		[self updateHistory];
		NSLog(@"after say");
		
	} @catch (NSException *e) {
		NSLog(@"send and say failed");
		NSLog(@"%@", e);
	}
	[connection invalidate];
	NSLog(@"said and done");
	[message setStringValue:@""];
}

-(void)updateHistory
{
	[historyDataString appendString:[message stringValue]];
}


-(void)connectionDown:(NSNotification *)note
{
	NSLog(@"connection down");
	
}

//from:  http://developer.apple.com/qa/qa2006/qa1454.html
- (BOOL)control:(NSControl*)control textView:(NSTextView*)textView doCommandBySelector:(SEL)commandSelector
{
    BOOL result = NO;
	
    if (commandSelector == @selector(insertNewline:))
    {
        // new line action:
        // always insert a line-break character and don’t cause the receiver to end editing
//        [textView insertNewlineIgnoringFieldEditor:self];
		NSLog(@"entered");
		[self sayRemote:textView];
        result = YES;
    }
    else if (commandSelector == @selector(insertTab:))
    {
        // tab action:
        // always insert a tab character and don’t cause the receiver to end editing
//        [textView insertTabIgnoringFieldEditor:self];
		NSLog(@"tab");
        result = YES;
    }
	
    return result;
}
@end
